package com.hfzy.ihk.common.core.freeswitch.robot;

/**
 * Created by Administrator on 2018/9/11.
 *
 * @author wws
 */

import com.alibaba.fastjson.JSON;
import com.hfzy.ihk.common.core.freeswitch.robot.support.EventName;
import org.freeswitch.esl.client.IEslEventListener;
import org.freeswitch.esl.client.inbound.Client;
import org.freeswitch.esl.client.inbound.InboundConnectionFailure;
import org.freeswitch.esl.client.transport.SendMsg;
import org.freeswitch.esl.client.transport.event.EslEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class EventSocketConfig {

    private static final Logger logger = LoggerFactory.getLogger(EventSocketConfig.class);

//    private static String    host   = "172.16.8.88";
//    private static String    host   = "192.168.1.101";
    private static String    host   = "172.16.6.56";
    private static int     port   = 8021;
    private static String    password = "ihkyanfa";
//    private static String    password = "1234";
    private Client client;

    private Map<String,Boolean> isAnswerMap=null;

    @Bean
    public Client initEventSocketClient() {

        client = new Client();

        isAnswerMap = new ConcurrentHashMap<>();
        try {
            client.connect(host, port, password, 10);
        } catch (InboundConnectionFailure e) {
            logger.error("Connect failed", e);
            return null;
        }

        //注册事件处理程序
        client.addEventListener(new IEslEventListener() {

            @Override
            public void eventReceived(EslEvent event) {

                logger.info("完整信息：" + JSON.toJSONString(event));

                String eventName = event.getEventHeaders().get("Event-Name");
//                String uuid = event.getEventHeaders().get("Core-UUID");//fs实例ID
                String uuid = event.getEventHeaders().get("Unique-ID");
                String channelUUid = event.getEventHeaders().get("Channel-Call-UUID");

                //sofia/internal/1000@172.16.19.189
                String ChannelName = event.getEventHeaders().get("Channel-Name");//通道名
                String ChannelState = event.getEventHeaders().get("Channel-State");//通道状态

                //主叫号码，（一个通道中）实际上就是主显号
                /*
                 比如 originate user/1005 &bridge({origination_caller_id_number=8888}user/1000)
                * a-leg中，主叫号码是0000000000，那么默认透传为主显号，1005电话上就显示了000000000，被叫是1005
                * b-leg中，由于主叫号码是1005，1000电话上显示1005。被叫是1000
                * */
                String Caller = event.getEventHeaders().get("Caller-Caller-ID-Number");
                //被叫号码，（一个通道中）实际上就是真实的2个端的号码(使用此区分mainCallPhone或targetCallPhone)
                String Callee = event.getEventHeaders().get("Caller-Callee-ID-Number");

                String aname = event.getEventHeaders().get("Caller-Caller-ID-Name");//主叫名，经纪人/客户姓名
                String bname = event.getEventHeaders().get("Caller-Callee-ID-Name");//被叫名，Outbound Call

                String destNum = event.getEventHeaders().get("Caller-Destination-Number");//通道对应目标号码


                switch (EventName.fromName(eventName)){
                    case CUSTOM:
                        logger.info("自定义：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case PRESENCE_IN:
                    case RE_SCHEDULE:
                        break;
                    case HEARTBEAT:
//                        logger.info("心跳：" + event.getEventBodyLines());
                        break;

                    case CHANNEL_DATA:
                        logger.info("CHANNEL_DATA：信道数据" + event.getEventBodyLines());
                        break;
                    case CHANNEL_GLOBAL:
                        logger.info("CHANNEL_GLOBAL：" + event.getEventBodyLines());
                        break;
                    case CHANNEL_HOLD:
                        logger.info("CHANNEL_HOLD：信道保持，使用uuid_hold或者接收SDP的readonly" + event.getEventBodyLines());
                        break;
                    case CHANNEL_PARK:
                        logger.info("CHANNEL_PARK：一个呼叫被挂起" + event.getEventBodyLines());
                        break;
                    case CHANNEL_UUID:
                        logger.info("CHANNEL_UUID：uuid事件表示唯一的ID通道已经改变。原来的ID将被报告的旧唯一ID。此事件会发生，当您使用参数origination_uuid时发出命令发起/桥。：" + event.getEventBodyLines());
                        break;
                    case CHANNEL_APPLICATION:
                        logger.info("CHANNEL_APPLICATION：信道产生的应用程序就是事件application=event一般用来捕获呼转" + event.getEventBodyLines());
                        break;

                    case CHANNEL_CREATE:
                        logger.info("CHANNEL_CREATE： 创建事件。 uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_PROGRESS:
                        logger.info("CHANNEL_PROGRESS 进度事件，外呼时对方提醒。或者入呼时提醒。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_ORIGINATE:
                        logger.info("CHANNEL_ORIGINATE 信道发起事件，触发完成发起：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_OUTGOING:
                        logger.info("CHANNEL_OUTGOING 创建一个外呼事件。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_PROGRESS_MEDIA:
                        logger.info("CHANNEL_PROGRESS_MEDIA 媒体进度事件，外呼时对方提醒。或者入呼时提醒。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_ANSWER:
                        logger.info("CHANNEL_ANSWER 呼叫应答事件。：uuid:{},channelUUid:{}",uuid,channelUUid);

                        String filePath_A = "C:\\Program Files\\FreeSWITCH\\recordings\\20181017\\"+uuid+"-in.PCMA";
                        String filePath_B = "C:\\Program Files\\FreeSWITCH\\recordings\\20181017\\"+uuid+"-out.PCMA";

                        System.out.println(filePath_A);
                        System.out.println(filePath_B);

                        InputStream ins_a = getFileInputStream(filePath_A);
                        InputStream ins_b = getFileInputStream(filePath_B);


                        if(isAnswerMap.get(uuid) == null) {
                            logger.info("首次应答，开始语音识别：{}",uuid);
//                            client.sendAsyncApiCommand("bgapi detect_speech", "unimrcp hello unimrcpserver-mrcp-v2");
                            SendMsg msg = new SendMsg(uuid);

                            msg.addCallCommand("execute");
                            msg.addExecuteAppName("detect_speech");
                            msg.addExecuteAppArg("unimrcp hello unimrcpserver-mrcp-v2");
                            client.sendMessage(msg);
                        }
                        isAnswerMap.put(uuid,true);
                        break;
                    case CHANNEL_BRIDGE:
                        logger.info("CHANNEL_BRIDGE：一个呼叫两个端点之间的桥接事件。" + event.getEventBodyLines());
                        break;
                    case CHANNEL_STATE:
                        logger.info("CHANNEL_STATE 呼叫状态事件。当一个信道切换通话状态时发送。此事件并不包含任何附加信息。。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_CALLSTATE:
                        logger.info("CHANNEL_CALLSTATE 信道呼叫状态事件。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_EXECUTE:
                        logger.info("CHANNEL_EXECUTE PBX正在执行呼叫事件。。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_EXECUTE_COMPLETE:
                        logger.info("CHANNEL_EXECUTE_COMPLETE 执行完成。。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_HANGUP:
                        logger.info("CHANNEL_HANGUP 挂断：uuid:{},channelUUid:{}，cause:{}",uuid,channelUUid,  event.getEventHeaders().get("Hangup-Cause"));
                        break;
                    case CHANNEL_HANGUP_COMPLETE:
                        logger.info("CHANNEL_HANGUP_COMPLETE ：挂断完成：uuid:{},channelUUid:{}",uuid,channelUUid);
                        isAnswerMap.remove(uuid);
//                        client.sendAsyncApiCommand("bgapi detect_speech", "stop");
//
                        SendMsg msg = new SendMsg(uuid);
                        msg.addCallCommand("execute");
                        msg.addExecuteAppName("detect_speech");
                        msg.addExecuteAppArg("stop");
                        client.sendMessage(msg);
                        break;
                    case CHANNEL_DESTROY:
                        logger.info("CHANNEL_DESTROY: 销毁事件。：uuid:{},channelUUid:{}",uuid,channelUUid);
                        break;
                    case CHANNEL_UNHOLD:
                        logger.info("CHANNEL_UNHOLD：触发后uuid_hold关闭<uuid>或者接收到INVITE SDP= SendRecv的" + event.getEventBodyLines());
                        break;
                    case CHANNEL_UNPARK:
                        logger.info("CHANNEL_UNPARK：一个呼叫被取消挂起" + event.getEventBodyLines());
                        break;
                    case CHANNEL_UNBRIDGE:
                        logger.info("CHANNEL_UNBRIDGE：停用桥接事件。" + event.getEventBodyLines());
                        break;

                    case RECV_RTCP_MESSAGE:
                        logger.info("RECV_RTCP_MESSAGE: {}",JSON.toJSONString(event));
                        break;

                    case PLAYBACK_START:
                        logger.info("PLAYBACK_START: 放音开始：sessionId:{},name:{}",uuid,"");
                        break;
                    case PLAYBACK_STOP:
                        logger.info("PLAYBACK_STOP: 放音结束：sessionId:{},name:{}",uuid,"");
                        break;
                    case RECORD_START:
                        logger.info("RECORD_START: 录音开始：sessionId:{},name:{}",uuid,"");
                        break;
                    case RECORD_STOP:
                        logger.info("RECORD_STOP: 录音结束：sessionId:{},name:{}",uuid,"");
                        break;
                    case DTMF:
                        logger.info("DTMF : 接收到按键 ：sessionId:{},name:{}",uuid, event.getEventBodyLines());
                        break;
                    case DETECTED_SPEECH:
                        logger.info("DETECTED_SPEECH： 语音识别结果：{}",JSON.toJSONString(event));
                        client.sendAsyncApiCommand("bgapi detect_speech", "resume");
                        msg = new SendMsg(uuid);
                        msg.addCallCommand("execute");
                        msg.addExecuteAppName("detect_speech");
                        msg.addExecuteAppArg("resume");
                        client.sendMessage(msg);
                        break;
                        default:
                            logger.warn("没有此事件类型:"+eventName);
                }

            }

            @Override
            public void backgroundJobResultReceived(EslEvent event) {
                String uuid = event.getEventHeaders().get("Job-UUID");
                logger.info(uuid+":Background job result received+:" + event.getEventName() + "/" + event.getEventHeaders());// +"/"+JoinString(event.getEventHeaders())+"/"+JoinString(event.getEventBodyLines()));
            }
        });

        //定义事件日志输出格式,但是java esl 目前只支持plain格式 ，http://wiki.freeswitch.org/wiki/Event_Socket
        //2012-12-25 19:20:30 [ main:426 ] - [ ERROR ] java.lang.IllegalStateException: Only 'plain' event format is supported at present
//        client.setEventSubscriptions("plain", "all");
        client.setEventSubscriptions("plain", "CHANNEL_CREATE CHANNEL_PROGRESS CHANNEL_ANSWER CHANNEL_HANGUP CHANNEL_BRIDGE DETECTED_SPEECH");
//        client.sendAsyncApiCommand("divert_events","on");
//        SendMsg msg = new SendMsg();
//        msg.addCallCommand("execute");
//        msg.addExecuteAppName("divert_events");
//        msg.addExecuteAppArg("on");
//        client.sendMessage(msg);
        System.out.println("连接完成");
        return client;
    }

    public Client getClient() {
        return client;
    }

    private InputStream getFileInputStream(String fileName){
        FileInputStream ins = null;
        try {
            File file = new File(fileName);
            if(!file.exists())
                return null;
            ins = new FileInputStream(file);
        } catch (Exception e) {
            System.out.println(e.fillInStackTrace());
        }
        return ins;
    }
}